class Test {
  static aaa = "3000"; //只有类和里面的静态方法可访问
  bbb = "4000"; //实例属性
  constructor(ddd) {
    //constructor方法是类的默认方法，创建类的实例化对象时被调用
    this.ccc = "5000";
    this.ddd = ddd;
    this.sayCCC();
    this.fun = () => {
      alert("我是实例上的方法");
    };
  }
  static sayAAA(val) {
    // console.log(this.aaa + val, this.bbb);
    return 789798;
  }

  sayCCC() {
    //方法都放在prototype里
    console.log(this.ddd, 999);
    // alert(this.ccc);
  }
}

// ES6 class继承
class TestSon extends Test {
  constructor(fff) {
    /**
     *super作为函数时，代表父类的构造函数
     *子类 constructor 方法中必须有 super ，且必须出现在 this 之前
     *注意：虽然super代表父类的构造函数，但此时返回的时TestSon的实例，
     *即super内部的this指的是TestSon的实例，因此super()相当于 Test.prototype.constructor.call(this)
     *
     *super作为对象时，在普通方法中，指向父类的原型对象，所以拿不到实例属性方法，在静态方法中，指向父类
     *super详细解释：https://blog.csdn.net/u013448372/article/details/111997556
     */
    super(fff);
    console.log(
      "super访问实例属性" + super.sayCCC,
      "super访问静态属性" + super.sayAAA,
      33
    );

    this.ccc = "子的5000";
    this.bbb = "子的4000";
  }
}

let test = new Test("我是constructor的实参");
let testSon = new TestSon("我是继承Test的TestSon的实参");
// console.log(test, Test);
console.log(test);
console.log(testSon);

// Test.sayAAA(1000)
// console.log(Test.bbb,test.bbb);
// console.log(test.sayAAA(888));
/**
 * 类里面属性和方法加了static,就为静态属性，只能被
 * 该类访问,实例化后是拿不到滴，静态的属性和方法先加载，
 * 所以在里面使用非静态的属性方法会拿到undefined
 */

// 定义一个动物类
function Animal(name) {
  let temp = '不加this'//错误写法，没声明，实例上也找不到该属性
  //实例属性

  this.name = name || "Animal";

  // 实例方法

  this.sleep = function () {
    console.log(this.name + "正在睡觉！");
  };
}

// 原型方法和属性
// Animal.prototype.name = "我是原型name";
Animal.prototype.eat = function (food) {
  console.log(this, "指向的是原型");
  console.log(this.name + "正在吃：" + food);
};

// Animal.prototype.eat('原型食物')//undefined正在吃：undefined
/**
 * 结果：
 * { name: '我是原型name', eat: [Function (anonymous)] } 指向的是原型
 * 我是原型name正在吃：原型食物
 *
 * 直接调用animal对象原型方法，那里面的值只能拿原型上的属性
 */

// let animal = new Animal("我是实例属性接收的name");
// animal.sleep();
// animal.eat("传值进来的食物");
/**
 * 结果：
 * 我是实例属性接收的name正在吃：实例食物
 *
 * 当实例上有对应属性和方法时，不会去原型上找
 */

//寄生组合式继承
function Cat(name) {
  Animal.call(this); //只能继承父类的实例属性和方法，不能继承原型属性/方法

  this.name = name || "Tom";
}

(function () {
  // 创建一个没有实例方法和属性的类

  var Super = function () {};

  Super.prototype = Animal.prototype;

  //将实例作为子类的原型？？？？？
  /**
    function P(){}
    function C(){}
    var p = new P();
    C.prototype = p;
    这样写的好处是子类如果更改了prototype，那么更改的东西也是附加到p这个实例上的
    如果你直接写C.prototype = P.prototype，那你对C的prototype的任何修改都会同时修改P的prototype
   */
  Cat.prototype = new Super();
})();

// Cat.prototype.constructor = Cat; // 需要修复下构造函数？？？？
//原型上的constructor就是指向当前构造函数，因为继承了父的原型，
//所以这个原型的constructor还是指向父，所以要赋值修改一下到当前
//https://blog.csdn.net/qq_35410544/article/details/93537395


var cat = new Cat();
console.log(cat);

console.log(cat.name);

console.log(cat.sleep());

console.log(cat instanceof Animal); // true

console.log(cat instanceof Cat); //true


// constructor构造函数理解：https://blog.csdn.net/Msinwln/article/details/106859046
//继承方式：https://m.php.cn/article/478459.html

//JavaScript 中的多态
//多态的字面意思就是多种状态，同一操作作用于不同的对象上，可以产生不同的解释和不同的执行结果
//多态最根本的作用就是通过把过程化的条件语句转化为对象的多态性，从而消除这些条件分支语句
//https://blog.csdn.net/CRMEB/article/details/120903302